package com.vladmr.sleepytimepicker;

import java.util.Calendar;

import android.app.ActionBar;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.AlarmClock;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.NumberPicker;
import android.widget.NumberPicker.OnValueChangeListener;
import android.widget.SimpleCursorAdapter;
import android.widget.SimpleCursorAdapter.ViewBinder;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;

import com.vladmr.sleepytimepicker.provider.SleepyTimeProvider;

public class ChooseFallasleepActivity extends FragmentActivity {
	private static final String TAG = "sleepytimepicker";
	private static final int REQUEST_CODE = 192837; // code for PendingIntent
	private static final int NOTIFICATION_ID = 1;
	private static final Uri CONTENT_URI = Uri
			.parse("content://com.vladmr.sleepytimepicker.provider.sleepytimeprovider");
	private static final String PATH_FALLASLEEP = "fallasleep";

	protected AppPreferences appPrefs;

	// alarm time
	int alarmHour, alarmMinute;

	// step in minutes (for custom timepicker)
	int minuteStep = 10;

	// boolean isReminder = false; // is it possible to set reminder?
	// if (getupTime-remainingTimeToSleep)>0 - true

	public static Uri buildFallaleepUri() {
		return CONTENT_URI.buildUpon().appendPath(PATH_FALLASLEEP).build();
	}

	public static Uri buildFallaleepIdUri(String str_id) {
		return CONTENT_URI.buildUpon().appendPath(PATH_FALLASLEEP)
				.appendPath(str_id).build();
	}

	public static PendingIntent getSyncPendingIntent(Context context) {
		Intent intent = new Intent(context, AlarmReceiver.class);
		PendingIntent sender = PendingIntent.getBroadcast(context,
				REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		return sender;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.choose_fallasleep_activity);

		if (android.os.Build.VERSION.SDK_INT >= 11) {
			ActionBar actionBar = getActionBar();
			actionBar.setDisplayHomeAsUpEnabled(true);
		}

		// loading default values from AppPreferences
		appPrefs = new AppPreferences(getApplicationContext());
		alarmHour = appPrefs.getAlarmHour();
		alarmMinute = appPrefs.getAlarmMinute();

		if (android.os.Build.VERSION.SDK_INT >= 11) {
			InitTimePicker11();
		} else {
			InitTimePicker9();
		}
		InitListView();
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (android.os.Build.VERSION.SDK_INT >= 11) {
			switch (item.getItemId()) {
			case android.R.id.home:
				// app icon in action bar clicked; go home
				Intent intent = new Intent(this, MainActivity.class);
				intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				startActivity(intent);
				return true;
			}
		}
		return super.onOptionsItemSelected(item);
	}

	private void InitTimePicker9() {
		TimePicker timepicker = (TimePicker) findViewById(R.id.timepicker7);
		timepicker.setIs24HourView(true);
		// disable popup keyboard
		timepicker
				.setDescendantFocusability(TimePicker.FOCUS_BLOCK_DESCENDANTS);

		timepicker.setOnTimeChangedListener(new OnTimeChangedListener() {
			@Override
			public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
				int hourchanged = hourOfDay - alarmHour;
				int minutechanged = minute - alarmMinute;

				// Log.i(TAG, "view values: hourOfDay = " +
				// view.getCurrentHour()
				// + ", minute = " + view.getCurrentMinute());
				// Log.i(TAG, "ontimechanged start: hourOfDay = " + hourOfDay
				// + ", minute = " + minute);
				// Log.i(TAG, "ontimechanged start: hourchange = " + hourchanged
				// + ", minutechange = " + minutechanged);
				if (hourchanged == 0 && minutechanged == 0) {
					SaveAlarmInPrefs();
					UpdateLayout();
				} else {
					if (hourchanged == 1 || hourchanged == -1
							|| hourchanged == 23) {
						alarmHour = hourOfDay;
						view.setCurrentHour(alarmHour);
					}

					// add minutes
					if (minutechanged == 1) {
						alarmMinute = alarmMinute + minuteStep;
						if (alarmMinute >= 60) {
							alarmMinute = alarmMinute - 60;
							if (alarmHour < 23) {
								alarmHour = alarmHour + 1;
							} else {
								alarmHour = 0;
							}
							view.setCurrentHour(alarmHour);
						}
						view.setCurrentMinute(alarmMinute);

						// remove minutes
					} else if (minutechanged == -1 || minutechanged == 59) {
						alarmMinute = alarmMinute - minuteStep;
						Log.i(TAG, "new alarm minute: " + alarmMinute);
						if (alarmMinute < 0) {
							alarmMinute = alarmMinute + 60;
							if (alarmHour > 0) {
								alarmHour = alarmHour - 1;
							} else {
								alarmHour = 23;
							}
							view.setCurrentHour(alarmHour);
						}
						view.setCurrentMinute(alarmMinute);
					}
				}
			}
		});
	}

	private void InitTimePicker11() {
		NumberPicker pickerHour = (NumberPicker) findViewById(R.id.numberPickerHour);
		NumberPicker pickerMinute = (NumberPicker) findViewById(R.id.numberPickerMinute);

		// disable popup keyboard
		pickerHour
				.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
		pickerMinute
				.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);

		pickerHour.setOnValueChangedListener(new OnValueChangeListener() {

			@Override
			public void onValueChange(NumberPicker picker, int oldVal,
					int newVal) {
				alarmHour = newVal;
				SaveAlarmInPrefs();
				UpdateLayout();
			}
		});

		pickerMinute.setOnValueChangedListener(new OnValueChangeListener() {

			@Override
			public void onValueChange(NumberPicker picker, int oldVal,
					int newVal) {
				int value = newVal * minuteStep;
				alarmMinute = value;
				SaveAlarmInPrefs();
				UpdateLayout();
			}
		});
	}

	/**
	 * timepicker API11
	 */
	private void SetTimePicker11() {
		NumberPicker pickerHour = (NumberPicker) findViewById(R.id.numberPickerHour);
		NumberPicker pickerMinute = (NumberPicker) findViewById(R.id.numberPickerMinute);

		pickerHour.setMinValue(0);
		pickerHour.setMaxValue(23);
		pickerHour.setValue(alarmHour);

		String[] minutes = new String[6];
		for (int i = 0; i < minutes.length; i++) {
			int value = i * minuteStep;
			if (value < 10) {
				minutes[i] = "0" + Integer.toString(value);
			} else {
				minutes[i] = Integer.toString(value);
			}

		}
		pickerMinute.setMinValue(0);
		pickerMinute.setMaxValue(minutes.length - 1);
		pickerMinute.setDisplayedValues(minutes);
		pickerMinute.setValue(alarmMinute / minuteStep);
		UpdateLayout();
	}

	private void InitListView() {
		final ListView lv = (ListView) findViewById(R.id.listview);

		lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int index,
					long arg3) {

				Cursor cursor = (Cursor) lv.getItemAtPosition(index);
				int position = cursor.getInt(cursor.getColumnIndex("_ID"));

				Bundle bundle = new Bundle();
				bundle.putInt("title", R.string.dialog_header);

				Calendar fallasleep_time = GetFallasleepTime(position);
				Calendar wakeup_time = GetWakeupTime(position);

				String str_fallasleep = FormatTime(
						fallasleep_time.get(Calendar.HOUR_OF_DAY),
						fallasleep_time.get(Calendar.MINUTE));
				String str_wakeup = FormatTime(
						wakeup_time.get(Calendar.HOUR_OF_DAY),
						wakeup_time.get(Calendar.MINUTE));

				Log.i(TAG, "listitemclick: fallasleeptime: " + str_fallasleep
						+ ", wakeuptime: " + str_wakeup);
				if ((fallasleep_time != null) && (wakeup_time != null)) {
					bundle.putInt("position", position);
					bundle.putString("reminder", str_fallasleep);
					bundle.putString("alarm", str_wakeup);

					if (android.os.Build.VERSION.SDK_INT >= 11) {
						android.app.DialogFragment fragment = new FallasleepDialogFragment11();
						fragment.setArguments(bundle);
						fragment.show(getFragmentManager(), "dialog");
					} else {
						android.support.v4.app.DialogFragment fragment = new FallasleepDialogFragment9();
						fragment.setArguments(bundle);
						fragment.show(getSupportFragmentManager(), "dialog");
						Log.i(TAG, "dialog started");
					}
				}
			}
		});
	}

	private Calendar GetFallasleepTime(int position) {
		// An array specifying which columns to return.
		String columns[] = new String[] { SleepyTimeProvider.Columns.ID,
				SleepyTimeProvider.Columns.TIME_FALLASLEEP,
				SleepyTimeProvider.Columns.TIME_WAKEUP };
		Uri uri = buildFallaleepIdUri(String.valueOf(position));
		Cursor cursor = getContentResolver().query(uri, columns, // Which
																	// columns
																	// to
																	// return
				null, // WHERE clause; which rows to return(all rows)
				null, // WHERE clause selection arguments (none)
				null // Order-by clause (ascending by name)
				);
		if (cursor.moveToFirst()) {
			Calendar fallasleep_time = Calendar.getInstance();
			fallasleep_time.setTimeInMillis(cursor.getLong(1));
			Log.i(TAG,
					"position: "
							+ position
							+ ", fallasleep_time: "
							+ FormatTime(
									fallasleep_time.get(Calendar.HOUR_OF_DAY),
									fallasleep_time.get(Calendar.MINUTE)));
			return fallasleep_time;
		} else {
			return null;
		}
	}

	private Calendar GetWakeupTime(int position) {
		// An array specifying which columns to return.
		String columns[] = new String[] { SleepyTimeProvider.Columns.ID,
				SleepyTimeProvider.Columns.TIME_FALLASLEEP,
				SleepyTimeProvider.Columns.TIME_WAKEUP };
		Uri uri = buildFallaleepIdUri(String.valueOf(position));
		Cursor cursor = getContentResolver().query(uri, columns, // Which
																	// columns
																	// to
																	// return
				null, // WHERE clause; which rows to return(all rows)
				null, // WHERE clause selection arguments (none)
				null // Order-by clause (ascending by name)
				);
		if (cursor.moveToFirst()) {
			Calendar wakeup_time = Calendar.getInstance();
			wakeup_time.setTimeInMillis(cursor.getLong(2));
			return wakeup_time;
		} else {
			return null;
		}
	}

	public void doPositiveDialogClick(int position, boolean reminder,
			boolean alarm) {
		if (reminder) {
			SetReminder(position);
		}

		if (alarm) {
			SetAlarm(position);
		}
	}

	public void doNegativeDialogClick() {
		// do nothing
	}

	@Override
	public void onResume() {
		super.onResume();

		if (android.os.Build.VERSION.SDK_INT >= 11) {
			SetTimePicker11();
		} else {
			TimePicker timepicker = (TimePicker) findViewById(R.id.timepicker7);
			timepicker.setCurrentHour(alarmHour);
			timepicker.setCurrentMinute(alarmMinute);
		}
	}

	@Override
	protected void onPause() {
		SaveAlarmInPrefs();
		super.onPause();
	}

	private void SaveAlarmInPrefs() {
		appPrefs.setAlarm(alarmHour, alarmMinute);
	}

	/**
	 * scheduling new reminder event in the system
	 */
	private void SetReminder(int position) {
		Context context = getApplicationContext();
		Calendar fallasleep_time = GetFallasleepTime(position);

		AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
		// test
		Calendar now = Calendar.getInstance();
		now.add(Calendar.MINUTE, 1);
		am.set(AlarmManager.RTC_WAKEUP, now.getTimeInMillis(),
				getSyncPendingIntent(context));
		Log.i(TAG,
				"test reminder: "
						+ FormatTime(now.get(Calendar.HOUR_OF_DAY),
								now.get(Calendar.MINUTE)));
		// END test
		// am.set(AlarmManager.RTC_WAKEUP, fallasleep_time.getTimeInMillis(),
		// getSyncPendingIntent(context));

		// show notification about active reminder
		NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		int icon = R.drawable.ic_launcher;
		long when = System.currentTimeMillis();
		CharSequence tickerText = "sleepytimepicker reminder";
		CharSequence contentTitle = "SleepyTimePicker";
		CharSequence contentText = "reminder ON ("
				+ FormatTime(fallasleep_time.get(Calendar.HOUR_OF_DAY),
						fallasleep_time.get(Calendar.MINUTE)) + ")";

		Intent notificationIntent = new Intent(context,
				NotificationsDialog.class);
		Bundle extra = new Bundle();
		extra.putString(
				"reminder",
				"reminder ON ("
						+ FormatTime(fallasleep_time.get(Calendar.HOUR_OF_DAY),
								fallasleep_time.get(Calendar.MINUTE)) + ")");
		notificationIntent.putExtras(extra);

		PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
				notificationIntent, Notification.FLAG_AUTO_CANCEL);

		if (android.os.Build.VERSION.SDK_INT >= 11) {
			Notification.Builder builder = new Notification.Builder(context);
			builder.setContentIntent(contentIntent).setSmallIcon(icon)
					.setTicker(tickerText).setWhen(when)
					.setContentTitle(contentTitle).setContentText(contentText);

			Notification notification = builder.getNotification();
			mNotificationManager.notify(NOTIFICATION_ID, notification);
		} else {
			// !!!API <11
			NotificationCompat.Builder builder = new NotificationCompat.Builder(
					context);
			builder.setContentIntent(contentIntent).setSmallIcon(icon)
					.setTicker(tickerText).setWhen(when)
					.setContentTitle(contentTitle).setContentText(contentText);

			Notification notification = builder.getNotification();
			mNotificationManager.notify(NOTIFICATION_ID, notification);
		}
		Log.i(TAG,
				"reminder set: "
						+ FormatTime(fallasleep_time.get(Calendar.HOUR_OF_DAY),
								fallasleep_time.get(Calendar.MINUTE)));
	}

	private void SetAlarm(int position) {
		if (android.os.Build.VERSION.SDK_INT >= 9) {
			Calendar alarm = GetWakeupTime(position);
			// launch AlarmClock application
			Intent setAlarm = new Intent(AlarmClock.ACTION_SET_ALARM);
			setAlarm.putExtra(AlarmClock.EXTRA_MESSAGE, "new alarm");
			setAlarm.putExtra(AlarmClock.EXTRA_HOUR,
					alarm.get(Calendar.HOUR_OF_DAY));
			setAlarm.putExtra(AlarmClock.EXTRA_MINUTES,
					alarm.get(Calendar.MINUTE));

			Log.i(TAG,
					"alarm set: "
							+ FormatTime(alarm.get(Calendar.HOUR_OF_DAY),
									alarm.get(Calendar.MINUTE)));
			startActivity(setAlarm);
		}
	}

	/**
	 * update the screen after timePickerAlarm changed
	 */
	@SuppressWarnings("deprecation")
	private void UpdateLayout() {
		ListView lv = (ListView) findViewById(R.id.listview);

		// An array specifying which columns to return.
		String columns[] = new String[] { SleepyTimeProvider.Columns.ID,
				SleepyTimeProvider.Columns.TIME_FALLASLEEP,
				SleepyTimeProvider.Columns.SLEEPYTIME,
				SleepyTimeProvider.Columns.TIME_WAKEUP,
				SleepyTimeProvider.Columns.TIME_OFFSET };

		Uri myUri = buildFallaleepUri();
		Cursor cursor = getContentResolver().query(myUri, columns, // Which
																	// columns
																	// to return
				null, // WHERE clause; which rows to return(all rows)
				null, // WHERE clause selection arguments (none)
				null // Order-by clause (ascending by name)
				);

		// THE DESIRED COLUMNS TO BE BOUND
		String[] lv_columns = new String[] {
				SleepyTimeProvider.Columns.TIME_FALLASLEEP,
				SleepyTimeProvider.Columns.SLEEPYTIME,
				SleepyTimeProvider.Columns.TIME_OFFSET };

		// THE XML DEFINED VIEWS WHICH THE DATA WILL BE BOUND TO
		int[] to = new int[] { R.id.item_time, R.id.item_sleepy, R.id.item_left };

		// CREATE THE ADAPTER USING THE CURSOR POINTING TO THE DESIRED DATA AS
		// WELL AS THE LAYOUT INFORMATION
		SimpleCursorAdapter adapter;
		if (android.os.Build.VERSION.SDK_INT >= 11) {
			adapter = new SimpleCursorAdapter(this, R.layout.fallasleep_item,
					cursor, lv_columns, to, 0);
		} else {
			adapter = new SimpleCursorAdapter(this, R.layout.fallasleep_item,
					cursor, lv_columns, to);
		}
		adapter.setViewBinder(new ViewBinder() {

			@Override
			public boolean setViewValue(View view, Cursor cursor,
					int columnIndex) {
				// columnIndex based on all columns in cursor
				String str_textview = "";
				try {
					long timeinmillis = cursor.getLong(columnIndex);
					Calendar calendar = Calendar.getInstance();
					calendar.setTimeInMillis(timeinmillis);
					switch (columnIndex) {
					case 1:
						str_textview = FormatTime(
								calendar.get(Calendar.HOUR_OF_DAY),
								calendar.get(Calendar.MINUTE));
						break;
					case 2:
						str_textview = FormatTimeToText(
								calendar.get(Calendar.HOUR_OF_DAY),
								calendar.get(Calendar.MINUTE));
						break;
					case 4:
						str_textview = FormatTimeToText(
								calendar.get(Calendar.HOUR_OF_DAY),
								calendar.get(Calendar.MINUTE));
						break;
					}
				} catch (Exception e) {
					str_textview = cursor.getString(columnIndex);
				}

				TextView textView = (TextView) view;
				textView.setText(str_textview);
				return true;
			}
		});
		lv.setAdapter(adapter);

		TextView tv_no_items = (TextView) findViewById(R.id.tv_no_items);
		LinearLayout header = (LinearLayout) findViewById(R.id.header);
		if (adapter.getCount() == 0) {
			tv_no_items.setVisibility(View.VISIBLE);
			header.setVisibility(View.INVISIBLE);
			lv.setVisibility(View.GONE);
			Log.i(TAG, "no_items");
		} else {
			tv_no_items.setVisibility(View.GONE);
			header.setVisibility(View.VISIBLE);
			lv.setVisibility(View.VISIBLE);
			Log.i(TAG, "items");
		}
	}

	// format calendar object into readable form: HH:mm
	protected String FormatTime(int hourOfDay, int minute) {
		String output = "";
		if (minute >= 10) {
			output = hourOfDay + ":" + minute;
		} else {
			output = hourOfDay + ":0" + minute;
		}
		return output;
	}

	// format calendar object into readable form: 7h 30min
	protected String FormatTimeToText(int hourOfDay, int minute) {
		String output = "";
		if (minute > 0) {
			output = hourOfDay + getString(R.string.hour) + " " + minute
					+ getString(R.string.minute);
		} else {
			output = hourOfDay + getString(R.string.hour);
		}
		return output;
	}

}